/*
 * 简单的 Echo 服务器示例
 * 使用 muduo 网络库
 */

#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/base/Logging.h>
#include <muduo/base/Timestamp.h>

#include <iostream>
#include <string>

using namespace muduo;
using namespace muduo::net;

class EchoServer {
public:
    EchoServer(EventLoop* loop, const InetAddress& listenAddr)
        : server_(loop, listenAddr, "EchoServer"),
          loop_(loop) {
        // 设置连接回调
        server_.setConnectionCallback(
            std::bind(&EchoServer::onConnection, this, _1));
        
        // 设置消息回调
        server_.setMessageCallback(
            std::bind(&EchoServer::onMessage, this, _1, _2, _3));
        
        // 设置线程数（IO 线程数）
        server_.setThreadNum(4);
    }

    void start() {
        server_.start();
    }

private:
    // 连接建立/断开回调
    void onConnection(const TcpConnectionPtr& conn) {
        LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
                 << conn->localAddress().toIpPort() << " is "
                 << (conn->connected() ? "UP" : "DOWN");
        
        if (conn->connected()) {
            conn->send("Welcome to EchoServer!\r\n");
        }
    }

    // 消息到达回调
    void onMessage(const TcpConnectionPtr& conn,
                   Buffer* buf,
                   Timestamp time) {
        // 读取所有数据
        string msg(buf->retrieveAllAsString());
        
        LOG_INFO << conn->name() << " echo " << msg.size() 
                 << " bytes at " << time.toString();
        
        // 回显消息
        conn->send(msg);
    }

    TcpServer server_;
    EventLoop* loop_;
};

int main(int argc, char* argv[]) {
    LOG_INFO << "pid = " << getpid();
    
    // 设置端口（默认 8080）
    uint16_t port = 8080;
    if (argc > 1) {
        port = static_cast<uint16_t>(atoi(argv[1]));
    }
    
    LOG_INFO << "Echo server listening on port " << port;
    
    EventLoop loop;
    InetAddress listenAddr(port);
    EchoServer server(&loop, listenAddr);
    
    server.start();
    loop.loop();  // 开始事件循环
    
    return 0;
}

